package com.caishi.lkx.order.pay;

import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.response.*;
import com.caishi.lkx.common.unionpay.sdk.*;
import com.caishi.lkx.order.OrderResultCode;
import com.caishi.lkx.order.model.PaymentModel;
import com.caishi.lkx.order.model.PaymentRefundLogModel;
import com.caishi.lkx.order.service.IOrderService;
import com.caishi.lkx.user.model.GroupModel;
import com.caishi.lkx.user.service.IGroupService;
import com.zzw.common.exception.BizRuntimeException;
import com.zzw.common.utils.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author by keray
 * date:2019/9/9 11:48
 */
@Slf4j
@Service
public class UnionPayPlugins implements PayPlugins {

    @Resource
    private IOrderService orderService;
    @Resource
    private IGroupService groupService;
    @Resource
    private SDKConfig sdkConfig;
    @Resource
    private AcpService acpService;

    private static final ConcurrentHashMap<Long, Object> lockMap = new ConcurrentHashMap<>();

    public enum UnionPayType {
        // app支付
        app,
        // h5 支付
        h5,
        // 二维码支付
        qrCode,
        // pc支付
        pc,
        unknown,
        ylshQrCode

    }

    @Override
    public boolean open() {
        return true;
    }

    @Override
    public Map<String, Object> sign(PaymentModel paymentModel, Object val, Map<String, Object> otherParam) {
        String response = null;
        try {
            if (val == UnionPayType.app) {
                //response = _appPay(paymentModel);
            } else if (val == UnionPayType.h5) {
                //response = _h5Pay(paymentModel);
            } else if (val == UnionPayType.qrCode) {
                //response = _qrPay(paymentModel);
            } else if (val == UnionPayType.pc) {
                response = _pcPay(paymentModel, otherParam);
            } else if (val == UnionPayType.ylshQrCode) {
                response = _ylshQrCodePay(paymentModel, otherParam);
            }  else {
                response = _defaultPay(paymentModel);
            }
            return MapUtil.of("body", response);
        } catch (Exception e) {
            log.error("支付宝支付签名异常:", e);
        }
        throw new BizRuntimeException(OrderResultCode.payFail);
    }

    private String _ylshQrCodePay(PaymentModel paymentModel, Map<String, Object> otherParam) throws Exception {
        var order = orderService.getById(paymentModel.getOrderId());
        Long groupId = order.getGroupId();
        if(groupId == null){
            log.error("平台id为空,订单号：{}",paymentModel.getOrderId());
            throw new BizRuntimeException("平台id为空");
        }
        GroupModel groupModel = groupService.getById(groupId);
        var config = groupModel.getUnionPayConfig();
        log.info("gourpid,{},config:{}",groupId,config);
        log.info("requestTimestamp:{}",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        //1. 组建请求报文
        GetQrCodeBody reqBody =
                GetQrCodeBody.builder()
        .requestTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
        .mid(config.get("mid").toString())
        .tid(config.get("tid").toString())
        .instMid(config.get("instMid").toString())
        .msgId(paymentModel.getId().toString())
        .totalAmount(paymentModel.getPaymentAmount().intValue())
        .notifyUrl(config.get("notifyUrl").toString())
        .returnUrl(config.get("returnUrl").toString())
        .counterNo(order.getId())
        .billNo(config.get("msgSrcId").toString()+paymentModel.getId())
        .billDate(paymentModel.getCreatedTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                        .build();
        log.info("signTimestamp:{}",DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()));
        String authorization = acpService.getAuthorization(config.get("appId").toString(),config.get("appKey").toString(), DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()), UUIDUtil.generateUUIDByTimestamp(),reqBody.toString());
        return new String(HttpsUtil.post(sdkConfig.getYlswQrCodeUrl(), reqBody.toString().getBytes(StandardCharsets.UTF_8), Map.of("Authorization",authorization)));
    }



    @Override
    public boolean prePayCallBack(PaymentModel paymentModel) {
        var order = orderService.getById(paymentModel.getOrderId());
        Long groupId = order.getGroupId();
        if(groupId == null || groupId == 0L){
            log.error("平台id为空,订单号：{}",paymentModel.getOrderId());
            return false;
        }
        GroupModel groupModel = groupService.getById(groupId);
        var config = groupModel.getUnionPayConfig();
        GetQrCodeBody reqBody = GetQrCodeBody.builder()
                .requestTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                .mid(config.get("mid").toString())
                .tid(config.get("tid").toString())
                .instMid(config.get("instMid").toString())
                .totalAmount(paymentModel.getPaymentAmount().intValue())
                .billNo(config.get("msgSrcId").toString()+paymentModel.getId())
                .billDate(paymentModel.getCreatedTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))).build();
        String authorization = null;
        try {
            authorization = acpService.getAuthorization(config.get("appId").toString(),config.get("appKey").toString(), DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()), UUIDUtil.generateUUIDByTimestamp(),reqBody.toString());
        } catch (Exception e) {
            log.error("组装银联请求头异常:{}",reqBody);
            throw new RuntimeException(e);
        }
        var resp =  JSON.parseObject( new String(HttpsUtil.post(sdkConfig.getYlswBillsQueryUrl(), reqBody.toString().getBytes(StandardCharsets.UTF_8), Map.of("Authorization",authorization))));
        var errorCode = resp.get("errCode");
        if("SUCCESS".equals(errorCode)){
            var status = resp.get("billStatus");
            if("PAID".equals(status)){
                return true;
            }
        }
        log.error("查询银联订单状态错误:{}",resp);
        return false;
    }

    @Override
    public boolean refund(PaymentModel paymentModel, PaymentRefundLogModel paymentRefundLogModel) {
        if (fetchRefund(paymentModel, paymentRefundLogModel)) {
            return true;
        }

        return false;
    }

    private boolean fetchRefund(PaymentModel paymentModel, PaymentRefundLogModel paymentRefundLogModel) {

        var order = orderService.getById(paymentModel.getOrderId());
        Long groupId = order.getGroupId();
        if(groupId == null){
            log.error("平台id为空,订单号：{}",paymentModel.getOrderId());
            throw new BizRuntimeException("平台id为空");
        }
        GroupModel groupModel = groupService.getById(groupId);
        var config = groupModel.getUnionPayConfig();
        //1. 组建请求报文
        GetQrCodeBody reqBody =
                GetQrCodeBody.builder()
                        .requestTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                        .mid(config.get("mid").toString())
                        .tid(config.get("tid").toString())
                        .instMid(config.get("instMid").toString())
                        .msgId(paymentModel.getId().toString())
                        .refundAmount(paymentRefundLogModel.getRefundAmount().intValue())
                        //.billNo(config.get("msgSrcId").toString()+order.getId().substring(6))
                        .billNo(config.get("msgSrcId").toString()+paymentModel.getId())
                        .billDate(paymentModel.getCreatedTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                        .build();
            String authorization = null;
            try {
                authorization = acpService.getAuthorization(config.get("appId").toString(),config.get("appKey").toString(), DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()), UUIDUtil.generateUUIDByTimestamp(),reqBody.toString());
            } catch (Exception e) {
                log.error("组装银联请求头异常:{}",reqBody);
                throw new RuntimeException(e);
            }
            var resp =  JSON.parseObject( new String(HttpsUtil.post(sdkConfig.getYlswBillsRefundUrl(), reqBody.toString().getBytes(StandardCharsets.UTF_8), Map.of("Authorization",authorization))));
            var errorCode = resp.get("errCode");
            if("SUCCESS".equals(errorCode)){
                var status = resp.get("billStatus");
                if("REFUND".equals(status)){
                    return true;
                }
            }
            log.error("查询银联订单状态错误:{}",resp);
            return false;
    }

    @Override
    public void orderCancel(PaymentModel paymentModel) {
//        try {
//            AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
//            AlipayTradeCloseModel model = new AlipayTradeCloseModel();
//            model.setOutTradeNo(paymentModel.getOrderSn());
//            OrderModel orderModel = orderService.getById(paymentModel.getOrderId());
//            getClient(orderModel.getGroupId()).execute(request);
//        } catch (Exception e) {
//            log.error("支付宝订单关闭异常", e);
//        }
    }

    private AlipayTradeAppPayResponse _appPay(PaymentModel paymentModel) throws AlipayApiException {


        return null;
    }

    @Deprecated
    private AlipayTradeWapPayResponse _h5Pay(PaymentModel paymentModel) throws AlipayApiException {

        return null;
    }

    private String _pcPay(PaymentModel paymentModel, Map<String, Object> otherParam) throws Exception {
        var order = orderService.getById(paymentModel.getOrderId());
        Long groupId = order.getGroupId();
        if(groupId == null){
            log.error("平台id为空,订单号：{}",paymentModel.getOrderId());
            throw new BizRuntimeException("平台id为空");
        }
        GroupModel groupModel = groupService.getById(groupId);

        Map<String, String> requestData = new HashMap<String, String>();
        /***银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改***/
        requestData.put("version", sdkConfig.getVersion());   			  //版本号，全渠道默认值
        requestData.put("encoding", SDKConstants.UTF_8_ENCODING); 			  //字符集编码，可以使用UTF-8,GBK两种方式
        requestData.put("signMethod",sdkConfig.getSignMethod() ); //签名方法
        requestData.put("txnType", "01");               			  //交易类型 ，01：消费
        requestData.put("txnSubType", "01");            			  //交易子类型， 01：自助消费
        requestData.put("bizType", "000201");           			  //业务类型，B2C网关支付，手机wap支付
        requestData.put("channelType", "07");           			  //渠道类型，这个字段区分B2C网关支付和手机wap支付；07：PC,平板  08：手机

        /***商户接入参数***/
        requestData.put("merId", groupModel.getUnionPayConfig().get("merId").toString());    	          			  //商户号码，请改成自己申请的正式商户号或者open上注册得来的777测试商户号
        requestData.put("accessType", "0");             			  //接入类型，0：直连商户
        requestData.put("orderId",paymentModel.getOrderId());             //商户订单号，8-40位数字字母，不能含“-”或“_”，可以自行定制规则
        requestData.put("txnTime", DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(order.getCreatedTime()));        //订单发送时间，取系统时间，格式为yyyyMMddHHmmss，必须取当前时间，否则会报txnTime无效
        requestData.put("currencyCode", "156");         			  //交易币种（境内商户一般是156 人民币）
        requestData.put("txnAmt", paymentModel.getPaymentAmount().toString());             			      //交易金额，单位分，不要带小数点
        requestData.put("riskRateInfo", orderService.getOrderOnlinePayTitle(paymentModel.getOrderId()));
        requestData.put("frontUrl", groupModel.getUnionPayConfig().get("frontUrl").toString());
        requestData.put("backUrl", groupModel.getUnionPayConfig().get("backUrl").toString());

        // 订单超时时间。
        // 超过此时间后，除网银交易外，其他交易银联系统会拒绝受理，提示超时。 跳转银行网银交易如果超时后交易成功，会自动退款，大约5个工作日金额返还到持卡人账户。
        // 此时间建议取支付时的北京时间加15分钟。
        // 超过超时时间调查询接口应答origRespCode不是A6或者00的就可以判断为失败。
        requestData.put("payTimeout", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date().getTime() + 15 * 60 * 1000));


//        /**请求参数设置完毕，以下对请求参数进行签名并生成html表单，将表单写入浏览器跳转打开银联页面**/
//        Map<String, String> submitFromData = acpService.sign(requestData,SDKConstants.UTF_8_ENCODING,groupModel.getUnionPayConfig());  //报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
//
//       // return AcpService.createAutoFormHtml(sdkConfig.getFrontTransUrl(), submitFromData,SDKConstants.UTF_8_ENCODING);
//        Map<String, String> h5requestData = new HashMap<String, String>();
//        h5requestData.put("msgSrc", "WWW.TEST.COM");
//        h5requestData.put("msgType", "trade.h5Pay");
//        h5requestData.put("requestTimestamp", order.getCreatedTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//        h5requestData.put("merOrderId", "3194"+order.getId());
//        h5requestData.put("mid", "898440165133308");
//        h5requestData.put("tid", "88880001");
//        h5requestData.put("totalAmount",paymentModel.getPaymentAmount().toString());
//        h5requestData.put("signType","SHA256");
//
     //   String sign  = SDKUtil.signSha256YLSH(h5requestData, "fcAmtnx7MwismjWNhNKdHC44mNXtnEQeJkRrhKJwyrW2ysRR", SDKConstants.UTF_8_ENCODING);
//        h5requestData.put("sign", sign);
//        String link = SDKUtil.createLinkString(h5requestData,true,true,SDKConstants.UTF_8_ENCODING);
//        var map = acpService.get("https://qr-test2.chinaums.com/netpay-portal/webpay/pay.do?"+link, SDKConstants.UTF_8_ENCODING);
//        System.out.println(map);




        //3. 发送http请求，并解析返回信息

        return null;
    }

    private String _qrPay(PaymentModel paymentModel) throws AlipayApiException {

        return null;
    }

    private String _defaultPay(PaymentModel paymentModel) throws AlipayApiException {

        return null;
    }



}
